Pneumonia Front (May 16, 2023)#
What is a Pneumonia Front?#
This is a term, originally coined by meteorologists in Milwaukee, Wisconsin, that refers to a strong cold front around the Great Lakes that leads to temperatures cooling very quickly, at a rate of 16 degrees Fahrenheit in 1 hour. These fronts can be quite common in the spring around Milwaukee and Chicagoland. We observed one of these fronts on May 16, 2023, observing this steep temperature decrease at one of our sensors at Northeastern Illinois University on the north side of Chicago, Illinois!
The Code to Create the Plots#
Show code cell source
import sage_data_client
from bokeh.models.formatters import DatetimeTickFormatter
import hvplot.pandas
import hvplot.xarray
import pytz
import holoviews as hv
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import xarray as xr
import matplotlib.pyplot as plt
from metpy.plots import USCOUNTIES
import metpy.calc as mpcalc
import act
import numpy as np
import pandas as pd
import warnings
from bokeh.models import DatetimeTickFormatter
import panel as pn
start="2023-05-16T22:00:00Z"
end="2023-05-17T00:00:00Z"
def apply_formatter(plot, element):
plot.handles['xaxis'].formatter = DatetimeTickFormatter(hours='%m/%d/%Y \n %H:%M',
minutes='%m/%d/%Y \n %H:%M',
hourmin='%m/%d/%Y \n %H:%M',
days='%m/%d/%Y \n %H:%M',
months='%m/%d/%Y \n %H:%M')
xr.set_options(keep_attrs=True)
warnings.filterwarnings("ignore")
hv.extension("bokeh")
# Dictionary for renaming to standard names
variable_rename_dict = {'wxt.env.humidity':'relative_humidity',
'wxt.env.pressure':'air_pressure',
'wxt.env.temp':'air_temperature',
'wxt.heater.temp':'heater_temperature',
'wxt.heater.volt':'heater_voltage',
'wxt.rain.accumulation':'rain_accumulation',
'wxt.wind.direction':'wind_direction',
'wxt.wind.speed':'wind_speed',
'sys.gps.lat':'latitude',
'sys.gps.lon':'longitude',
}
# Dictionary for units that are missing
units_dict = {'wxt.env.temp': 'degC',
'wxt.env.pressure':'hPa',
'wxt.env.humidity':'percent',
'wxt.wind.speed':'m/s',
'wxt.wind.direction':'degrees'}
def generate_data_array(df, variable, rename_variable_dict=variable_rename_dict):
new_variable_name = rename_variable_dict[variable]
df_variable= df.loc[df.name == variable]
ds = df_variable.to_xarray().rename({'value':new_variable_name,
'timestamp':'time',
'meta.vsn':'node'})
ds[new_variable_name].attrs['units'] = df_variable['meta.units'].values[0]
ds['time'] = pd.to_datetime(ds.time)
ds.attrs['datastream'] = ds.node.values[0]
return ds[[new_variable_name]]
def generate_dataset(df, variables, rename_variable_dict=variable_rename_dict):
try:
reindexed = df.set_index(['meta.vsn', 'timestamp'])
except:
reindexed = df.set_index(['timestamp'])
return xr.merge([generate_data_array(reindexed, variable) for variable in variables])
# Query and load for n numbder of days
wxt_df = sage_data_client.query(
start=start,
end=end,
filter={
"sensor": "vaisala-wxt536",
"name": "wxt.env.*"
}
)
wxt_df1 = sage_data_client.query(
start=start,
end=end,
filter={
"sensor": "vaisala-wxt536",
"name": "wxt.wind.*"
}
)
# Use local Chicago times
wxt_df = pd.concat([wxt_df, wxt_df1])
#time = pd.to_datetime(wxt_df.timestamp.values, utc=True)
#wxt_df['timestamp'] = time.tz_convert(pytz.timezone("America/Chicago"))
try:
# Discover what variables we have and what to load into xarray
wxt_variables = wxt_df.name.unique()
wxt_df['meta.units'] = wxt_df.name.map(units_dict)
wxt_ds = generate_dataset(wxt_df, wxt_variables).squeeze().metpy.parse_cf()
wxt_ds['node'] = ['W08D at Northeastern Illinois University']
# Convert to Local Chicago Time - THIS IS ONLY FOR DAYLIGHT TIME
wxt_ds['time'] = wxt_ds.time - pd.Timedelta(hours=5)
wxt_ds['air_dewpoint_temperature'] = mpcalc.dewpoint_from_relative_humidity(wxt_ds.air_temperature, wxt_ds.relative_humidity)
# Convert to degrees Fahrenheit
wxt_ds['air_temperature'] = wxt_ds['air_temperature'].metpy.quantify().metpy.convert_units('degF').metpy.dequantify()
wxt_ds['air_dewpoint_temperature'] = wxt_ds['air_dewpoint_temperature'].metpy.quantify().metpy.convert_units('degF').metpy.dequantify()
wxt_ds['wind_speed'] = wxt_ds['wind_speed'].metpy.quantify().metpy.convert_units('mph').metpy.dequantify()
# Resample to 1 minute freqency
minute_ds = wxt_ds.resample(time='1T').mean()
plots = []
temp_plot = wxt_ds.air_temperature.hvplot(color='red',
xlabel='Local Time (Chicago)',
label='Air Temperature (degF)')
dewp_plot = wxt_ds.air_dewpoint_temperature.hvplot(color='green',
xlabel='Local Time (Chicago)',
label='Dewpoint Temperature (degF)')
plots.append((temp_plot * dewp_plot).opts(hooks=[apply_formatter]))
meteogram_variables = ['wind_speed', 'wind_direction']
for variable in meteogram_variables:
plots.append((wxt_ds[variable].hvplot.line(label='10 Hz Data') *
minute_ds[variable].hvplot.line(label='1 Minute Data')).opts(hooks=[apply_formatter]))
except:
plots = pn.Row(title='No Data Available')
---------------------------------------------------------------------------
TimeoutError Traceback (most recent call last)
File ~/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/urllib/request.py:1348, in AbstractHTTPHandler.do_open(self, http_class, req, **http_conn_args)
1347 try:
-> 1348 h.request(req.get_method(), req.selector, req.data, headers,
1349 encode_chunked=req.has_header('Transfer-encoding'))
1350 except OSError as err: # timeout error
File ~/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/http/client.py:1283, in HTTPConnection.request(self, method, url, body, headers, encode_chunked)
1282 """Send a complete request to the server."""
-> 1283 self._send_request(method, url, body, headers, encode_chunked)
File ~/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/http/client.py:1329, in HTTPConnection._send_request(self, method, url, body, headers, encode_chunked)
1328 body = _encode(body, 'body')
-> 1329 self.endheaders(body, encode_chunked=encode_chunked)
File ~/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/http/client.py:1278, in HTTPConnection.endheaders(self, message_body, encode_chunked)
1277 raise CannotSendHeader()
-> 1278 self._send_output(message_body, encode_chunked=encode_chunked)
File ~/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/http/client.py:1038, in HTTPConnection._send_output(self, message_body, encode_chunked)
1037 del self._buffer[:]
-> 1038 self.send(msg)
1040 if message_body is not None:
1041
1042 # create a consistent interface to message_body
File ~/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/http/client.py:976, in HTTPConnection.send(self, data)
975 if self.auto_open:
--> 976 self.connect()
977 else:
File ~/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/http/client.py:1448, in HTTPSConnection.connect(self)
1446 "Connect to a host on a given (SSL) port."
-> 1448 super().connect()
1450 if self._tunnel_host:
File ~/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/http/client.py:942, in HTTPConnection.connect(self)
941 sys.audit("http.client.connect", self, self.host, self.port)
--> 942 self.sock = self._create_connection(
943 (self.host,self.port), self.timeout, self.source_address)
944 # Might fail in OSs that don't implement TCP_NODELAY
File ~/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/socket.py:857, in create_connection(address, timeout, source_address)
856 try:
--> 857 raise err
858 finally:
859 # Break explicitly a reference cycle
File ~/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/socket.py:845, in create_connection(address, timeout, source_address)
844 sock.bind(source_address)
--> 845 sock.connect(sa)
846 # Break explicitly a reference cycle
TimeoutError: [Errno 110] Connection timed out
During handling of the above exception, another exception occurred:
URLError Traceback (most recent call last)
Cell In[1], line 75
71 return xr.merge([generate_data_array(reindexed, variable) for variable in variables])
74 # Query and load for n numbder of days
---> 75 wxt_df = sage_data_client.query(
76 start=start,
77 end=end,
78 filter={
79 "sensor": "vaisala-wxt536",
80 "name": "wxt.env.*"
81 }
82 )
84 wxt_df1 = sage_data_client.query(
85 start=start,
86 end=end,
(...)
90 }
91 )
93 # Use local Chicago times
File ~/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/site-packages/sage_data_client/query.py:115, in query(start, end, head, tail, filter, endpoint, bucket, experimental_func, experimental_window)
112 headers = {"Accept-Encoding": "gzip"}
113 req = Request(endpoint, data, headers=headers)
--> 115 with urlopen(req) as f:
116 content_encoding = f.headers.get("Content-Encoding", "")
117 if "gzip" in content_encoding:
File ~/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/urllib/request.py:216, in urlopen(url, data, timeout, cafile, capath, cadefault, context)
214 else:
215 opener = _opener
--> 216 return opener.open(url, data, timeout)
File ~/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/urllib/request.py:519, in OpenerDirector.open(self, fullurl, data, timeout)
516 req = meth(req)
518 sys.audit('urllib.Request', req.full_url, req.data, req.headers, req.get_method())
--> 519 response = self._open(req, data)
521 # post-process response
522 meth_name = protocol+"_response"
File ~/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/urllib/request.py:536, in OpenerDirector._open(self, req, data)
533 return result
535 protocol = req.type
--> 536 result = self._call_chain(self.handle_open, protocol, protocol +
537 '_open', req)
538 if result:
539 return result
File ~/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/urllib/request.py:496, in OpenerDirector._call_chain(self, chain, kind, meth_name, *args)
494 for handler in handlers:
495 func = getattr(handler, meth_name)
--> 496 result = func(*args)
497 if result is not None:
498 return result
File ~/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/urllib/request.py:1391, in HTTPSHandler.https_open(self, req)
1390 def https_open(self, req):
-> 1391 return self.do_open(http.client.HTTPSConnection, req,
1392 context=self._context, check_hostname=self._check_hostname)
File ~/miniconda3/envs/instrument-cookbooks-dev/lib/python3.10/urllib/request.py:1351, in AbstractHTTPHandler.do_open(self, http_class, req, **http_conn_args)
1348 h.request(req.get_method(), req.selector, req.data, headers,
1349 encode_chunked=req.has_header('Transfer-encoding'))
1350 except OSError as err: # timeout error
-> 1351 raise URLError(err)
1352 r = h.getresponse()
1353 except:
URLError: <urlopen error [Errno 110] Connection timed out>
View the Data!#
Here, we are looking at the Temperature (red), Dewpoint (green), and Wind Speed and Direction (blue). Notice the temperature drop at around 5:30 PM local time, and the increase in wind speed!
Show code cell source
display(hv.Layout(plots).opts(title='CROCUS Observations at Northeastern Illinois').cols(1))